

#ifndef _IOSCHEDULER_H
#define _IOSCHEDULER_H


#include "Coroutine.h"
#include "Scheduler.h"
#include "Timer.h"
#include <atomic>
#include <cstddef>
#include <functional>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <vector>


namespace zepco {


class IOManager : public Scheduler, public TimerManager {
  public:
    enum Event {
        NONE = 0x0,
        READ = 0x1, // == EPOLLIN
        WRITE = 0x4 // == EPOLLOUT
    };

  private:
    struct FDContext {
        struct EventContext {
            Scheduler *scheduler = nullptr;
            std::shared_ptr<Zephyr> zephyr;
            std::function<void()> callback;
        };

        int fd;
        Event events = NONE; // 当前注册的事件
        EventContext read; // read event context
        EventContext write; // write event context

        std::mutex mutex;
        // 获取对应事件的上下文
        EventContext &getEventContext(Event event);
        /**
         * @brief 重置上下文
         * 
         * @param eventcontext [out]需要重置的上下文
         */
        void resetEventContext(EventContext &eventcontext);
        // 触发事件event 根据event事件类型调用对应上下文结构调度器去调度协程或函数
        void triggerEventContext(Event event);
    };

  public:
    IOManager(size_t threads = 1, bool use_caller = true, const std::string &name = "IOManager");
    ~IOManager();

    // 添加一个事件到fd上 并设置回调函数
    int addEvent(int fd, Event event, std::function<void()> callback = nullptr);
    // 删除fd上的一个事件
    bool delEvent(int fd, Event event);
    // 删除fd上的一个事件并触发回调函数
    bool cancelEvent(int fd, Event event);
    // 删除fd上的所有事件并触发所有的回调函数
    bool cancelAll(int fd);

    static IOManager *GetThis();

  protected:

    // 通知调度器有任务调度
    // 写pipe让idle协程从epoll_wait退出 待idle协程yield之后Scheduler::run就可以调度其他任务
    void tickle() override;
    // 判断调度器是否可以停止
    // Scheduler::stopping() && IOManager::m_pendingEventCount == 0 表示没有io事件可调度
    bool stopping() override;
    // idle协程只负责收集所有已触发的fd回调函数并加入调度器任务队列
    // 真正执行的时机未idle协程退出后下一轮调度执行
    void idle() override;
    //  定时器被插入到最前面式触发tickle 唤醒epoll_wait
    void onTimerInsertAtFront() override;
    // 调整文件描述符的上下文数组的大小
    void contextResize(size_t size);

  private:
    int m_epfd; // epoll fd
    // 线程间通信管道 fd[0] read fd[1] write
    int m_tickleFDs[2];
    // 记录待处理的事件数量
    std::atomic<size_t> m_pendingEventCount{0};
    // 读写锁
    std::shared_mutex m_mtx;
    // 文件描述符上下文数组
    std::vector<FDContext *> m_fdContexts;
};




}


#endif // _IOSCHEDULER_H